import axios from "axios";

class ErnieService {
  constructor() {
    this.accessToken = null;
    this.tokenExpiresAt = 0;
    this.requestTimeout = 300000;
    this.maxContextLength = 10;
  }

  async getAccessToken() {
    const now = Math.floor(Date.now() / 1000);
    if (this.isTokenValid(now)) {
      return this.accessToken;
    }

    try {
      const { access_token, expires_in } = await this.fetchAccessToken();
      this.updateToken(access_token, now + expires_in);
      return access_token;
    } catch (error) {
      console.error("获取百度 access_token 失败:", error.message);
      throw new Error("获取百度 access_token 失败");
    }
  }

  isTokenValid(now) {
    return this.accessToken && this.tokenExpiresAt > now;
  }

  async fetchAccessToken() {
    const API_KEY = process.env.ERNIE_API_KEY;
    const SECRET_KEY = process.env.ERNIE_SECRET_KEY;
    const url = `https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=${API_KEY}&client_secret=${SECRET_KEY}`;
    
    const response = await axios.post(url);
    const { access_token, expires_in } = response.data;
    
    if (!access_token) {
      throw new Error("获取 access_token 失败");
    }

    return { access_token, expires_in };
  }

  updateToken(token, expiresAt) {
    this.accessToken = token;
    this.tokenExpiresAt = expiresAt;
  }

  processContext(context = [], newMessage) {
    const safeContext = Array.isArray(context) ? context : [];
    
    safeContext.push({
      role: "user",
      content: newMessage
    });

    return safeContext.slice(-this.maxContextLength);
  }

  validateContext(context) {
    if (!Array.isArray(context)) return false;
    
    return context.every(msg => 
      msg?.role && 
      ['user', 'assistant'].includes(msg.role) &&
      typeof msg.content === 'string'
    );
  }

  async chat(message, context = [], retries = 3) {
    const messages = this.processContext(context, message);

    if (!this.validateContext(messages)) {
      throw new Error("上下文格式无效");
    }

    for (let attempt = 0; attempt < retries; attempt++) {
      try {
        const response = await this.makeApiRequest(messages);
        return this.handleApiResponse(response, messages);
      } catch (error) {
        if (!this.shouldRetry(attempt, retries, error)) {
          throw error;
        }
        await this.delay(attempt);
      }
    }
  }

  async makeApiRequest(messages) {
    const accessToken = await this.getAccessToken();
    const url = `https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions?access_token=${accessToken}`;

    return axios.post(url, { messages }, {
      timeout: this.requestTimeout,
      headers: { 'Content-Type': 'application/json' }
    });
  }

  handleApiResponse(response, messages) {
    if (response.data.error_code) {
      throw new Error(`ERNIE Bot 错误: ${response.data.error_msg}`);
    }

    const updatedMessages = [...messages, {
      role: "assistant",
      content: response.data.result
    }];

    return {
      reply: response.data.result,
      context: updatedMessages
    };
  }

  shouldRetry(attempt, maxRetries, error) {
    return attempt < maxRetries - 1;
  }

  async delay(attempt) {
    const waitTime = 1000 * Math.pow(2, attempt);
    await new Promise(resolve => setTimeout(resolve, waitTime));
  }

  clearContext() {
    return [];
  }

  mergeContexts(context1 = [], context2 = []) {
    return [...context1, ...context2].slice(-this.maxContextLength);
  }

  getContextSummary(context) {
    if (!Array.isArray(context) || context.length === 0) {
      return { messageCount: 0, lastMessage: null, totalLength: 0 };
    }

    return {
      messageCount: context.length,
      lastMessage: context[context.length - 1],
      totalLength: context.reduce((sum, msg) => sum + msg.content.length, 0)
    };
  }
}

export default new ErnieService();